//== SAGITTARIUS ============================================================================

//== FILEDOC =========================================================================

/** @file lParser.h
  * @brief Parser for lexer command language expressions
  * @details The BNF of the command language grammar is as follows:<br><br>
  * 
  * Assignment -> id = E <br>
  * id -> [anything_but_ctrl_char]* <br>
  * E  -> OE' (expression) <br>
  * E' -> &OE' | 𝜀 (left-factored form) <br>
  * O  -> TO' (operand) <br>
  * O' -> |TO' | 𝜀 (left-factored) <br>
  * T  -> FT' (term) <br>
  * T' -> FT' | 𝜀 (left-factored) <br>
  * F  -> (E) | @a sym | ^(E) | ^ @a sym | (E)* | @a sym * | ^(E)* | ^ @a sym * (factor) <br>
  * @a sym -> Single symbol or character class; may not contain control characters (primitive type)
  * 
  * @par Control Characters
  * --Not guaranteed to be comprehensive-- <br>
  * \<blank\> \\t \\n \\r & ( ) * ^ | [ ] \\ - \\0
  * 
  * @page LexerBNF
  * @b Lexer @b Command @b Language @b Grammar <br>
  * The BNF of the command language grammar is as follows:<br><br>
  * 
  * Assignment -> id = E <br>
  * id -> [anything_but_ctrl_char]* <br>
  * E  -> OE' (expression) <br>
  * E' -> &OE' | 𝜀 (left-factored form) <br>
  * O  -> TO' (operand) <br>
  * O' -> |TO' | 𝜀 (left-factored) <br>
  * T  -> FT' (term) <br>
  * T' -> FT' | 𝜀 (left-factored) <br>
  * F  -> (E) | @a sym | ^(E) | ^ @a sym | (E)* | @a sym * | ^(E)* | ^ @a sym * (factor) <br>
  * @a sym -> Single symbol of character class; may not contain control characters (primitive type)
  * 
  * @par Control Characters
  * --Not guaranteed to be comprehensive-- <br>
  * \<blank\> \\t \\n \\r & ( ) * ^ | [ ] \\ - \\0
  */

//== BEGINNING OF CODE ===============================================================

#ifndef __SAGUTTARUIS__REPARSER__H_
#define __SAGUTTARUIS__REPARSER__H_

//== INCLUDES ========================================================================

#include "sagittarius/core/SagittariusCore.h"
#include "sagittarius/lexer/lAST.h"
#include "sagittarius/lexer/lexvec.h"

#ifdef __cplusplus
extern "C" {
#endif

/** @def LEXPARSER_COMPUTE_NULLABLE 
 * @brief Compute the nullable property on-line if defined
 */
#define LEXPARSER_COMPUTE_NULLABLE

/**
 * @brief Holds the parser state with respect to the input buffer; actual state info is implied by recursion
 */
typedef struct {
    constLexBuf w;
} lparserState;

/**
 * @brief Holds essential configuration infor for parser
 */
typedef struct {
    LXAlphaType emptychr;
} lparserInfo;

//-- Variables --

typedef struct {
    /// Name of the variable, as declared
    LexBuf name;
    /// Initial value
    uint64 initval;
    /// Does this var have an initial value?
    int haveintv; //rename to haveinit?
} lexvar;

/** @brief Tries to match the string on the given input
 * @param[in,out] state Parser state
 * @param[in] str Null-terminated string to match
 * @details The input cursor is advanced if the string matches
 * in full (excluding the obligatory terminating null char). If not, 
 * the input cursor is unaffected.
 */
int l_trymatchstr(lparserState* state, const char* str);

/**
 * @returns The created parser state
 * @param[in] w The buffer of characters to parse
 * @brief Create an initial parser state
 */
lparserState lex_createParserState(constLexBuf w);

/** @brief Matches the given symbol
 * @details The symbol is consumed if it matches
 */
int lmatch(lparserState* state, LXFixedType c);

/**
 * @param[in,out] state The parser state
 * @param[in] pi Essential configuration infor for parser
 * @brief Discard whitespace
 */
void lex_parseWS(lparserState* state, lparserInfo* pi);

/**
 * @return The variable
 * @param[in,out] state The parser state
 * @param[in] pi Essential configuration infor for parser
 * @brief Parse a variable definition
 */
lexvar lex_parseVar(lparserState* state, lparserInfo* pi);

/**
 * @return A new AST node representing the assignment
 * @param[in,out] state The parser state
 * @param[in] pi Essential configuration infor for parser
 * @brief Parse an assignment with backtracking
 */
lexvece* lex_parseAssn(lparserState* state, lparserInfo* pi);

/**
 * @return A buffer containing the ID
 * @param[in,out] state The parser state
 * @param[in] pi Essential configuration infor for parser
 * @brief Parse an identifier (see @ref LexerBNF "BNF definition")
 */
LexBuf lex_parseID(lparserState* state, lparserInfo* pi);

/** @brief Parses an unsigned int
 */
uint64 lex_parseUInt(lparserState* state, lparserInfo* pi);

/**
 * @return A buffer containing the expression
 * @param[in,out] state The parser state
 * @param[in] pi Essential configuration infor for parser
 * @details Parses a @a string containing the RE, and returns
 * it as a buffer. Also resets the cursor to the position it
 * was in when the function was called.
 */
LexBuf lex_parseExpStr(lparserState* state, lparserInfo* pi);

//RE-level

/**
 * @return A new AST node representing the expansion
 * @param[in,out] state The parser state
 * @param[in] pi Essential configuration infor for parser
 * @brief Parse the expansion E  -> OE'
 */
lASTNode* lex_parseExpE(lparserState* state, lparserInfo* pi);
/**
 * @return A new AST node representing the expansion
 * @param[in,out] state The parser state
 * @param[in] pi Essential configuration infor for parser
 * @brief Parse the expansion E' -> &OE' | 𝜀
 */
lASTNode* lex_parseExpEp(lparserState* state, lparserInfo* pi);
/**
 * @return A new AST node representing the expansion
 * @param[in,out] state The parser state
 * @param[in] pi Essential configuration infor for parser
 * @brief Parse the expansion O  -> TO'
 */
lASTNode* lex_parseExpO(lparserState* state, lparserInfo* pi);
/**
 * @return A new AST node representing the expansion
 * @param[in,out] state The parser state
 * @param[in] pi Essential configuration infor for parser
 * @brief Parse the expansion O' -> |TO' | 𝜀
 */
lASTNode* lex_parseExpOp(lparserState* state, lparserInfo* pi);
/**
 * @return A new AST node representing the expansion
 * @param[in,out] state The parser state
 * @param[in] pi Essential configuration infor for parser
 * @brief Parse the expansion T  -> FT'
 */
lASTNode* lex_parseExpT(lparserState* state, lparserInfo* pi);
/**
 * @return A new AST node representing the expansion
 * @param[in,out] state The parser state
 * @param[in] pi Essential configuration infor for parser
 * @brief Parse the expansion T' -> FT' | 𝜀
 */
lASTNode* lex_parseExpTp(lparserState* state, lparserInfo* pi);
/**
 * @return A new AST node representing the expansion
 * @param[in,out] state The parser state
 * @param[in] pi Essential configuration infor for parser
 * @brief Parse the expansion F  -> (E) | @a sym | ^(E) | ^ @a sym | (E)* | @a sym * | ^(E)* | ^ @a sym *
 */
lASTNode* lex_parseExpF(lparserState* state, lparserInfo* pi);

//Terminal expression(s)
/**
 * @return A new AST node representing the expansion
 * @param[in,out] state The parser state
 * @param[in] pi Essential configuration infor for parser
 * @brief Parse the expansion sym -> single symbol or character class
 */
lASTNode* lex_parseExpPrimitive(lparserState* state, lparserInfo* pi);

/**
 * @brief Parses an escaped symbol
 * @param[in,out] state The parser state
 * @param[in] pi Essential configuration infor for parser
 * @param[out] c Stores the parsed symbol
 * @details RE syntax specifies different escaping for characters inside a character
 * set. For parsing escaped chars inside a character set use @ref lex_parseSetEscapedSymbol
 * Parameter note: @a c comes last in the parameter list to make things easier for the
 * ABI. It can pass @a state and @a pi in registers without saving anything
 * in the previous frame (because the previous frame was probably one of these
 * parsing functions that takes state & pi as args)
 */
void lex_parseEscapedSymbol(lparserState* state, lparserInfo* pi, LXAlphaType* c);

/**
 * @brief Parses an escaped symbol <b> in a character set </b>
 * @param[in,out] state The parser state
 * @param[in] pi Essential configuration infor for parser
 * @param[out] c Stores the parsed symbol
 * @details For parsing escaped chars outside of a character set use @ref lex_parseEscapedSymbol
 * Parameter note: @a c comes last in the parameter list to make things easier for the
 * ABI. It can pass @a state and @a pi in registers without saving anything
 * in the previous frame (because the previous frame was probably one of these
 * parsing functions that takes state & pi as args)
 */
void lex_parseSetEscapedSymbol(lparserState* state, lparserInfo* pi, LXAlphaType* c);

/**
 * @brief Parse a single-line comment '#...'
 * @param[in,out] state The parser state
 * @param[in] pi Essential configuration infor for parser
 * @details Consumes until the end of the line. Multiline comments can
 * be achieved by escaping the newline character with '\'.
 */
void lex_parseComment(lparserState* state, lparserInfo* pi);

#ifdef __cplusplus
}//extern "C"
#endif

#endif
